using System;

namespace Com.FirstSolver.Splash;

public abstract class ECPoint
{
	internal readonly ECCurve curve;

	internal readonly ECFieldElement x;

	internal readonly ECFieldElement y;

	internal readonly bool withCompression;

	public ECCurve mCurve => curve;

	public ECFieldElement mX => x;

	public ECFieldElement mY => y;

	public bool IsInfinity => x == null && y == null;

	public bool IsCompressed => withCompression;

	protected internal abstract bool YTilde { get; }

	protected internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
	{
		if (curve == null)
		{
			throw new ArgumentNullException("curve");
		}
		this.curve = curve;
		this.x = x;
		this.y = y;
		this.withCompression = withCompression;
	}

	public abstract ECPoint Add(ECPoint b);

	public abstract ECPoint Subtract(ECPoint b);

	public abstract ECPoint Negate();

	public abstract ECPoint Twice();

	public virtual byte[] GetEncoded(ECPointCompressionFlag flag = ECPointCompressionFlag.None)
	{
		if (IsInfinity)
		{
			return new byte[1];
		}
		byte[] X = x.GetEncoded();
		int YIndex = X.Length + 1;
		byte[] R;
		if (flag.Equals(ECPointCompressionFlag.Compression))
		{
			R = new byte[YIndex];
			R[0] = (byte)(y.ToBigInteger().TestBit(0) ? 3u : 2u);
		}
		else
		{
			byte[] Y = y.GetEncoded();
			R = new byte[YIndex + Y.Length];
			if (flag.Equals(ECPointCompressionFlag.None))
			{
				R[0] = 4;
			}
			else
			{
				R[0] = (byte)(y.ToBigInteger().TestBit(0) ? 7u : 6u);
			}
			Y.CopyTo(R, YIndex);
		}
		X.CopyTo(R, 1);
		return R;
	}

	public virtual ECPoint Multiply(BigInteger k)
	{
		if (k.SignValue < 0)
		{
			throw new ArgumentException("The multiplicator cannot be negative", "k");
		}
		if (IsInfinity)
		{
			return this;
		}
		if (k.SignValue == 0)
		{
			return curve.Infinity;
		}
		BigInteger h = k.Multiply(BigInteger.Three);
		ECPoint neg = Negate();
		ECPoint R = this;
		for (int i = h.BitLength - 2; i > 0; i--)
		{
			R = R.Twice();
			bool hBit = h.TestBit(i);
			bool eBit = k.TestBit(i);
			if (hBit != eBit)
			{
				R = R.Add(hBit ? this : neg);
			}
		}
		return R;
	}

	public override bool Equals(object obj)
	{
		if (obj == this)
		{
			return true;
		}
		if (!(obj is ECPoint o))
		{
			return false;
		}
		if (IsInfinity)
		{
			return o.IsInfinity;
		}
		return x.Equals(o.x) && y.Equals(o.y);
	}

	public override int GetHashCode()
	{
		if (IsInfinity)
		{
			return 0;
		}
		return x.GetHashCode() ^ y.GetHashCode();
	}
}
